/*
 * Copyright (C) 2022 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

#include "desktopdatahandler.h"
#include <QThread>
#include <QDebug>
#include "utils.h"
#include "appcategorymanager.h"

DesktopDataHandler::DesktopDataHandler(QObject *parent)
    : QObject(parent)
{
    qRegisterMetaType<QMap<quint32,QList<quint32> >>("QMap<quint32,QList<quint32> >");
    qRegisterMetaType<QMap<quint32,QList<quint32> >>("QMap<quint32, QList<QList<quint32>>>");
    qRegisterMetaType<QMap<int,UKUI::BaseItem*>>("QMap<int,UKUI::BaseItem*>");
    qRegisterMetaType<QMap<UKUI::BaseItem::Categories, QList<quint32>>>("QMap<UKUI::Categories, QList<quint32>>");
    qRegisterMetaType<QList<QList<quint32> >>("QList<QList<quint32> >");
    qRegisterMetaType<QList<quint32> >("QList<quint32>");
}

DesktopDataHandler::~DesktopDataHandler()
{
    m_dataBackend->deleteLater();
}

QList<UKUI::ItemId> DesktopDataHandler::apps() const
{
    return m_apps;
}

QMap<int, UKUI::BaseItem *> DesktopDataHandler::items() const
{
    return m_itemsData;
}

QMap<UKUI::BaseItem::Categories, QList<UKUI::ItemId>> DesktopDataHandler::categoriesItems() const
{
    return m_categoriesItems;
}

QString DesktopDataHandler::translatedName(const QString &sourceName)
{
    return UKUI::translatedName(sourceName);
}

void DesktopDataHandler::init()
{
    m_dataBackend = new UKUI::DesktopDataProvider();
    m_pageData = m_dataBackend->getAllItemIdsInPage();
    m_setData = m_dataBackend->getAllItemIdsInSet();
    m_itemsData = m_dataBackend->getAllItems();
    Q_EMIT desktopData(m_pageData, m_setData, m_itemsData);

    m_apps = m_dataBackend->getAllAppIdList();
    m_categoriesItems.clear();
    auto categoryIntList = AppCategoryManager::categoryIntList();
    for (auto &category : qAsConst(categoryIntList)) {
        m_categoriesItems.insert((UKUI::BaseItem::Categories)category,
             m_dataBackend->getAppIdListAccordingCategory((UKUI::BaseItem::Categories)category));
    }
    Q_EMIT categoriesData(m_categoriesItems);

    connect(m_dataBackend, SIGNAL(itemAdded(int, int)), this, SLOT(addItem(int, int)));
    connect(m_dataBackend, &UKUI::DesktopDataProvider::taskbarAppIdAdded, this, &DesktopDataHandler::addItemIdToTaskbar);
    connect(m_dataBackend, &UKUI::DesktopDataProvider::iconThemeChanged,
            this, &DesktopDataHandler::iconThemeChanged);
    connect(m_dataBackend, &UKUI::DesktopDataProvider::itemRemovedFromHomeScreen, this, &DesktopDataHandler::onItemRemovedFromHomeScreen);
    connect(m_dataBackend, &UKUI::DesktopDataProvider::itemRemovedFromSet, this, &DesktopDataHandler::onItemRemovedFromSet);
    connect(m_dataBackend, &UKUI::DesktopDataProvider::appIdTakedFromTaskbar, this, &DesktopDataHandler::onAppIdTakedFromTaskbar);
    connect(m_dataBackend, &UKUI::DesktopDataProvider::appIdTakedFromSet, this, &DesktopDataHandler::onAppIdTakedFromSet);
    connect(m_dataBackend, &UKUI::DesktopDataProvider::appIdTakedFromHomeScreen, this, &DesktopDataHandler::onAppIdTakedFromHomeScreen);

    connect(m_dataBackend, &UKUI::DesktopDataProvider::taskbarAppIdPosExchanged, this, &DesktopDataHandler::onTaskbarAppIdPosExchanged);
    connect(m_dataBackend, &UKUI::DesktopDataProvider::eduCategoryChanged, this, &DesktopDataHandler::onEduCategoryChanged);
    connect(this, &DesktopDataHandler::uninsatllApp, m_dataBackend, &UKUI::DesktopDataProvider::uninsatllApp);
    connect(this, &DesktopDataHandler::replaceGroupIdWithAppId, m_dataBackend, &UKUI::DesktopDataProvider::replaceGroupIdWithAppId);
    connect(m_dataBackend, &UKUI::DesktopDataProvider::appCategoryChanged, this, &DesktopDataHandler::changeAppCategory);
    connect(this, &DesktopDataHandler::itemStateChanged, m_dataBackend, &UKUI::DesktopDataProvider::updateWidgetState);
}

void DesktopDataHandler::setGroupName(const QString &name, int groupId)
{
    if (!m_setData.contains(groupId)) {
        return;
    }
    m_dataBackend->setSetName(groupId, name);
}

void DesktopDataHandler::updateGroup(int groupId, const QList<QList<int> > &ids)
{
    Q_ASSERT(m_setData.contains(groupId));
    if (m_setData.value(groupId) == ids) {
        return;
    }
    m_dataBackend->updateSet(groupId, ids);
    m_setData[groupId] = ids;
    qDebug() << __func__ << "handler" << m_setData.value(groupId) << groupId;
}

void DesktopDataHandler::updateHomeScreenPage(const QList<QList<int> > &ids)
{
    int homeScreenPageDiff = ids.count() - m_pageData.count();
    if (homeScreenPageDiff != 0) {
        int tmp = qAbs(homeScreenPageDiff);
        for (int i=0; i<tmp; ++i) {
            if (homeScreenPageDiff > 0) {
                m_dataBackend->addHomeScreenPage();
            } else {
                m_dataBackend->deleteHomeScreenPage();
            }
        }
    }
    int page = 0;
    for (page = 0; page<ids.count(); ++page) {
        updateHomeScreenIds(page, ids.at(page));
    }
    while (page < m_pageData.count()) {
        m_pageData.remove(page);
        ++page;
    }
}

void DesktopDataHandler::createGroup(int groupId, const QString &groupName, const QList<int> &itemIdList)
{
    m_dataBackend->createGroup(groupId, groupName, itemIdList);
    updateDekstopData();
}

void DesktopDataHandler::removeGroup(quint32 groupId)
{
    m_setData.remove(groupId);
    m_dataBackend->removeGroup(groupId);
}

void DesktopDataHandler::updateDekstopData()
{
    m_pageData = m_dataBackend->getAllItemIdsInPage();
    m_setData = m_dataBackend->getAllItemIdsInSet();
    m_itemsData = m_dataBackend->getAllItems();
    m_apps = m_dataBackend->getAllAppIdList();
    updateEducategory();
}

void DesktopDataHandler::addItem(int itemId, int page)
{
    bool newCategory = false;
    int indexOfAllCategory = 0;
    int indexOfCategory = 0;
    int category = 0;

    auto categoryIntList = AppCategoryManager::categoryIntList();
    for (auto &_category : qAsConst(categoryIntList)) {
        UKUI::BaseItem::Categories categoryEnum = static_cast<UKUI::BaseItem::Categories>(_category);
        auto newCategoryItems = m_dataBackend->getAppIdListAccordingCategory((UKUI::BaseItem::Categories)_category);
        if (m_categoriesItems.value(categoryEnum) != newCategoryItems) {
            if (m_categoriesItems.value(categoryEnum).isEmpty()) {
                newCategory = true;
            } else {
                indexOfCategory = newCategoryItems.indexOf(itemId);
            }
            category = static_cast<int>(_category);
            break;
        }
    }

    updateDekstopData();
    qDebug() << __func__ << "handler" << m_pageData.value(page);
    indexOfAllCategory = m_apps.indexOf(itemId);

    Q_EMIT appInstalled(itemId, indexOfAllCategory, indexOfCategory, page, newCategory, category);
}

void DesktopDataHandler::addItemIdToTaskbar(int itemId, int insertPosIndex)
{
    if (m_setData.value(0).at(0).count() < insertPosIndex) {
        qWarning() << __func__ << "add itemId to group failed !!!";
        return;
    }
    m_setData[0][0].insert(insertPosIndex, itemId);
    qDebug() << __func__ << m_setData.value(0).at(0);
    Q_EMIT itemIdMovedToTaskbar(itemId, insertPosIndex);
}

void DesktopDataHandler::removeItem(quint32 itemId, int page)
{
    Q_UNUSED(itemId)
    Q_UNUSED(page)
    updateDekstopData();
}

void DesktopDataHandler::iconThemeChanged()
{
    m_itemsData = m_dataBackend->getAllItems();
    Q_EMIT iconChanged();
}

void DesktopDataHandler::onTaskbarAppIdPosExchanged(const QList<int> &appIdListAfterChange)
{
    if (m_setData.empty() || m_setData.value(0).isEmpty()) {
        qWarning() << __func__ << "m_setData is empty !!!";
        return;
    }
    qDebug() << __func__ << "handle" << m_setData.value(0) << appIdListAfterChange;

    QList<int> tmpAppIdList = m_setData.value(0).at(0);
    for (int i = 0; i < appIdListAfterChange.count(); ++i) {
        int tmpAppId = appIdListAfterChange.at(i);
        int idIndexOf = tmpAppIdList.indexOf(tmpAppId);
        if (idIndexOf == i) {
            continue;
        }
        if (idIndexOf > 0 && i < tmpAppIdList.count()) {
            m_setData[0][0].move(idIndexOf, i);
            tmpAppIdList = m_setData.value(0).at(0);
            qDebug() << m_setData.value(0).at(0);
            Q_EMIT taskbarAppPosExchanged(idIndexOf, i);
            qDebug() << __func__ << "handle" << idIndexOf << i;
        }
    }
}

void DesktopDataHandler::changeAppCategory(const quint32 itemId, const QList<int> newCategory)
{
    if (newCategory.count() <= 0) {
        qWarning() << __func__ << "new category is incorrect!!!";
        return;
    }
    for (int categoryId = 0; categoryId < newCategory.count(); ++categoryId) {
        int category = newCategory[categoryId];
        for (int i = 0; i < m_categoriesItems.count(); ++i) {
            UKUI::BaseItem::Categories key = m_categoriesItems.keys().at(i);
            QList<UKUI::ItemId> itemIdList = m_categoriesItems[key];
            int itemIdIndexOf = itemIdList.indexOf(itemId);
            if (itemIdIndexOf >= 0 && key != category) {
                m_categoriesItems[key].removeAt(itemIdIndexOf);
            }
            if (key == category && itemIdIndexOf < 0) {
                m_categoriesItems[key].push_back(itemId);
            }
        }
    }
    Q_EMIT appCategoryChanged(itemId, newCategory);
}

void DesktopDataHandler::onItemRemovedFromHomeScreen(int itemId, int page)
{
    Q_EMIT appUninstalled(itemId, page);
    updateDekstopData();
    qDebug() << __func__ << "handler" << m_pageData;
}

void DesktopDataHandler::onItemRemovedFromSet(int itemId, int setId)
{
    Q_EMIT appUninstalledFromGroup(itemId, setId);
    updateDekstopData();
    qDebug() << __func__ << "handler" << m_setData.value(setId);
}

void DesktopDataHandler::onAppIdTakedFromTaskbar(int itemId)
{
    Q_EMIT itemIdTakedFromTaskbar(itemId);
    updateDekstopData();
    qDebug() << __func__ << "handler" << m_setData.value(0);
}

void DesktopDataHandler::onAppIdTakedFromSet(int itemId, int setId)
{
    Q_EMIT itemIdTakedFromGroup(itemId, setId);
    updateDekstopData();
    qDebug() << __func__ << "handler" << m_setData.value(setId);
}

void DesktopDataHandler::onAppIdTakedFromHomeScreen(int itemId, int page)
{
    Q_EMIT itemIdTakedFromDesktop(itemId, page);
    updateDekstopData();
    qDebug() << __func__ << "handler" << m_pageData;
}

void DesktopDataHandler::onEduCategoryChanged()
{
    updateEducategory();
    Q_EMIT categoriesData(m_categoriesItems);
}

int DesktopDataHandler::groupIdOfItem(int itemId)
{
    auto it = m_setData.constBegin();
    while(it != m_setData.constEnd()) {
        for (const auto &page : it.value()) {
            if (page.contains(itemId)) {
                return it.key();
            }
        }
        ++ it;
    }
    return -1;
}

void DesktopDataHandler::updateHomeScreenIds(int page, const QList<int> &ids)
{
    m_dataBackend->updateHomeScreenPageIds(page, ids);
    m_pageData[page] = ids;
    qDebug() << __func__ << "handler" << page << ids;
}

void DesktopDataHandler::updateEducategory()
{
    auto categoryIntList = AppCategoryManager::categoryIntList();
    for (auto &category : qAsConst(categoryIntList)) {
        m_categoriesItems.insert((UKUI::BaseItem::Categories)category,
             m_dataBackend->getAppIdListAccordingCategory((UKUI::BaseItem::Categories)category));
    }
}

